﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using BCCommon;
using BCCommon.Enums;
using BCCommon.Exceptions;
using BCCommon.Extensions;
using BCDto.Common.Payment.Payment;
using BCDto.Common.Payment.PaymentRecord;
using BCService.Common.Payment.Payment;
using BCCommon.PaymentEnums;
using BCService.Common.Payment.PaymentRecord;
using BCTMSRESTful.Configs;
using BCService.Common.Payment.PaymentBusiness;
using System.Web;
using System.Net;

namespace BCTMSRESTful.Controllers.Management.TSM
{
    [Route("api/v1/sim/[controller]")]
    [ApiExplorerSettings(GroupName = "TMSAdmin")]
    public class AgentPaymentsController : ManagementBaseController
    {
        private readonly IPaymentService paymentService;
        private readonly ICommonPaymentRecordService commonPaymentRecordService;
        private readonly IPaymentBusinessService paymentBusinessService;
        public AgentPaymentsController(
            IPaymentBusinessService paymentBusinessService,
            IPaymentService paymentService,
            ICommonPaymentRecordService commonPaymentRecordService)
        {
            this.paymentService = paymentService;
            this.commonPaymentRecordService = commonPaymentRecordService;
            this.paymentBusinessService = paymentBusinessService;
        }

        /// <summary>
        /// 获取用户支付记录细列表
        /// </summary>  
        /// <param name="pageIndex">当前页码</param>
        /// <param name="pageSize">每页数据条数</param>
        /// <response code="200">获取用户支付记录明细列表</response>
        /// <returns></returns>
        [HttpGet]
        [ProducesResponseType(typeof(PageableList<PaymentRecordDto>), 200)]
        public IActionResult Get(
            [FromQuery(Name = "index")] int pageIndex = 1,
            [FromQuery(Name = "size")] int pageSize = 10)
        {
            return Ok(this.commonPaymentRecordService.GetPaymentRecordsByAgentRecordId(pageIndex, pageSize, this.Admin.AgentRecord.AgentRecordId));
        }


        #region 获取代理商可用支付渠道
        /// <summary>
        /// 获取代理商可用的付款渠道。
        /// </summary>
        /// <param name="orderType">订单类型。</param>
        /// <param name="osType">操作系统。</param>
        /// <param name="deviceType">设备类型。</param>
        /// <response code="200">付款渠道列表。</response>
        /// <returns></returns>
        [HttpGet("[action]")]
        [ProducesResponseType(typeof(IEnumerable<ChannelDto>), 200)]
        public IActionResult Channels([FromQuery(Name = "order_type")] FlowType orderType, [FromQuery(Name = "os_type")] SourceOSType osType, 
            [FromQuery(Name = "device_type")] DeviceType deviceType)
        {
            var channels = this.paymentService.GetAgentChannels( SourceAppType.StaffApp, orderType, osType, this.Admin.AgentRecord.AgentRecordId);

            return this.Ok(channels);
        }
        #endregion

        #region 获取代理商提现渠道
        /// <summary>
        /// 获取代理商可用的付款渠道。
        /// </summary>
        /// <param name="osType">操作系统。</param>
        /// <param name="deviceType">设备类型。</param>
        /// <response code="200">付款渠道列表。</response>
        /// <returns></returns>
        [HttpGet("[action]")]
        [ProducesResponseType(typeof(IEnumerable<ChannelDto>), 200)]
        public IActionResult TransferChannels([FromQuery(Name = "os_type")] SourceOSType osType, [FromQuery(Name = "device_type")] DeviceType deviceType)
        {
            PaymentChannelType[] supportedChannels = new PaymentChannelType[] { PaymentChannelType.Alipay, PaymentChannelType.Weixin };

            var channels = this.paymentService.GetTransferChannels(SourceAppType.StaffApp, FlowType.CashOut, osType).Where(p => p.ChannelId.AsEnum<PaymentChannelType>().In(supportedChannels));

            return this.Ok(channels);
        }
        #endregion
        /// <summary>
        /// 统一付款接口，创建付款请求。
        /// </summary>
        /// <param name="requestDto">付款请求信息。</param>
        /// <response code="200">付款结果。</response>
        /// <returns></returns>
        [HttpPost]
        [ProducesResponseType(typeof(PaymentDto), 200)]
        public IActionResult Create2([FromBody] PaymentRequestDto requestDto)
        {
            var ip = Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = HttpContext.Connection.RemoteIpAddress.ToString();
            }
            IChannelFactoryService channelService = this.paymentService.GetChannelService(requestDto.AppType, requestDto.ChannelType, requestDto.OSType);

            if (channelService == null)
            {
                throw new ArgumentException("选定的付款渠道暂时无法使用。");
            }
            if (requestDto.OrderType == FlowType.AgentRecharge)
            {
                if (requestDto.Amount <= 0)
                {
                    throw new ArgumentException("充值金额必须大于 0 元。");
                }

                //string rechargeNo = RandomCode.GeneratePaymentOrderNo();
                string rechargeNo = Admin.AgentRecord.AgentRecordId.ToString();

                PaymentDto paymentDto = channelService.AgentTryPay(requestDto.AppType, FlowType.AgentRecharge, FlowType.AgentRecharge.ToString(), 
                    rechargeNo, requestDto.OSType, requestDto.DeviceType, requestDto.DeviceId, requestDto.Parameters, 
                    requestDto.Amount, SourcePayerType.Company, this.Admin);

                return this.Ok(paymentDto);
            }

            throw new ArgumentException($"用户端不支持类型为 {requestDto.OrderType.GetDisplayString()} 的订单付款。");
        }

        /// <summary>
        /// 同步订单状态。
        /// </summary>
        /// <param name="paymentRecordId">支付记录编号。</param>
        /// <param name="requestDto"></param>
        /// <response code="200">付款结果。</response>
        /// <returns></returns>
        [HttpPost("{payment_record_id}/[action]")]
        [ProducesResponseType(typeof(PaymentDto), 200)]
        public IActionResult AgentSynchronize([FromRoute(Name = "payment_record_id")] long paymentRecordId, [FromBody] PaymentSynchronizeRequestDto requestDto)
        {
            var paymentRecord = commonPaymentRecordService.GetPaymentRecord(paymentRecordId);

            if (paymentRecord == null)
            {
                throw new ObjectNotFoundException();
            }

            var channelFactoryService = this.paymentService.GetChannelService(SourceAppType.StaffApp, 
                paymentRecord.PaymentChannelId.AsEnum<PaymentChannelType>(), paymentRecord.OSType.AsEnum<SourceOSType>());

            if (channelFactoryService == null)
            {
                throw new ArgumentException("原订单的付款渠道暂时无法使用。");
            }

            paymentRecord = channelFactoryService.Synchronize(paymentRecordId, requestDto);

            if (paymentRecord.CheckSignTime == null && paymentRecord.Status == PaymentResultType.Success)
            {
                // 同步原始订单状态
                this.paymentService.AgentSynchronize(this.Admin, paymentRecord);
            }

            var paymentDto = new PaymentDto
            {
                PaymentRecordId = paymentRecord.PaymentRecordId,
                OrderType = paymentRecord.OrderType,
                ReferenceNumber = paymentRecord.ReferenceNumber,
                PayChannelType = paymentRecord.PaymentChannelId,
                OriginalAmount = paymentRecord.Amount,
                Discount = paymentRecord.Discount,
                Result = paymentRecord.Status
            };

            if (paymentDto.Result == PaymentResultType.Success)
            {
                paymentDto.PaidAmount = paymentRecord.Amount - paymentRecord.Discount;
                paymentDto.PaidTime = paymentRecord.SuccessTime;
            }

            return this.Ok(paymentDto);
        }


        #region 创建余额充值请求
        /// <summary>
        /// 创建余额充值请求。
        /// </summary>
        /// <param name="dto">付款请求信息。</param>
        /// <response code="200">付款结果。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(PaymentDto), 200)]
        [Obsolete]
        public IActionResult BalanceRecharge([FromBody] RechargeRequestDto dto)
        {
            var ip = Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = HttpContext.Connection.RemoteIpAddress.ToString();
            }
            IChannelFactoryService channelService = this.paymentService.GetChannelService(SourceAppType.WebsiteApp, dto.ChannelType, dto.OSType);

            if (channelService == null)
            {
                throw new ArgumentException("选定的付款渠道暂时无法使用。");
            }

            decimal originalAmount = dto.Amount;

            string rechargeNo = string.Empty;

            if (dto.OrderType == FlowType.Recharge)
            {
                rechargeNo = this.Admin.AgentRecord.AgentRecordId.ToString();
            }
            if (originalAmount <= 0)
            {
                throw new NotImplementedException();
            }

            Console.WriteLine(rechargeNo);

            PaymentDto paymentDto = channelService.AgentTryPay(SourceAppType.WebsiteApp, FlowType.Recharge, "代理商充值", rechargeNo, dto.OSType,
                dto.DeviceType, dto.DeviceId, dto.Parameters, originalAmount, SourcePayerType.Customer, this.Admin);

            return this.Ok(paymentDto);
        }

        /// <summary>
        /// 余额充值验签（支付宝、微信、银行卡使用此接口）
        /// </summary>
        /// <param name="rechargeRequestDto">余额充值付款请求信息。</param>
        /// <response code="200">订单付款二维码信息。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [Obsolete]
        public IActionResult RechargeCheckSign([FromBody] RechargeRequestDto rechargeRequestDto)
        {
            if (rechargeRequestDto.ChannelType == PaymentChannelType.Balance)
            {
                throw new ArgumentException("此方法不支持余额支付");
            }

            //if (rechargeRequestDto.ChannelType == PaymentChannelType.Cash)
            //{
            //    throw new ArgumentException("此方法不支持线下支付");
            //}

            if (rechargeRequestDto.ChannelType == PaymentChannelType.BankCard)
            {
                throw new ArgumentException("此方法暂不支持银行卡支付");
            }

            IChannelFactoryService channelFactoryService = this.paymentService.GetChannelService(SourceAppType.StaffApp, rechargeRequestDto.ChannelType,
                rechargeRequestDto.OSType);

            if (channelFactoryService == null)
            {
                throw new ArgumentException("选定的付款渠道暂时无法使用。");
            }

            if (rechargeRequestDto.OrderType != FlowType.Recharge)
            {
                throw new ArgumentException("余额充值验签，不支持其他类型");
            }

            if (rechargeRequestDto.ChannelType == PaymentChannelType.Alipay)
            {
                if (rechargeRequestDto.Parameters == null || rechargeRequestDto.Parameters.Count == 0)
                {
                    throw new ArgumentException("网络平台使用费验签缺少必要信息,请检查Parameters是否存在信息");
                }
            }

            PaymentRecordDto paymentRecordDto = channelFactoryService.SyncCheckSign(rechargeRequestDto.Parameters);

            if (paymentRecordDto == null)
            {
                throw new ArgumentException("同步回调验签失败");
            }

            return this.Ok();

            //if (paymentRecordDto != null)
            //{
            //    if (paymentRecordDto.CheckSignTime.HasValue)
            //    {
            //        PaymentDto paymentDto = new PaymentDto()
            //        {
            //            PaymentRecordId = paymentRecordDto.PaymentRecordId,
            //            OrderType = paymentRecordDto.OrderType,
            //            ReferenceNumber = paymentRecordDto.ReferenceNumber,
            //            PayChannelType = rechargeRequestDto.ChannelType,
            //            OriginalAmount = paymentRecordDto.Amount,
            //            Discount = 0M,
            //            PaidAmount = paymentRecordDto.Amount,
            //            Result = PaymentResultType.Success
            //        };
            //        this.commonPaymentRecordService.UpdatePaymentRecordStatusSuccess(paymentRecordDto.PaymentRecordId);
            //    }
            //    return this.Ok();
            //}

            //throw new ArgumentException("验签失败");
        }
        #endregion

        //#region 余额支付
        ///// <summary>
        ///// 余额支付（支付宝、微信、银行卡无法使用此接口）
        ///// </summary>
        ///// <param name="balancePayRequestDto">订单付款请求信息。</param>
        ///// <response code="200">订单付款二维码信息。</response>
        ///// <returns></returns>
        //[HttpPost("[action]")]
        //public IActionResult OrderPayBalance([FromBody]BalancePayRequestDto balancePayRequestDto)
        //{
        //    if (balancePayRequestDto.ChannelType != PaymentChannelType.Balance)
        //    {
        //        throw new ArgumentException("此方法仅支持余额支付");
        //    }

        //    IChannelFactoryService channelFactoryService = this.paymentService.GetChannelService(AppType.ClientApp, balancePayRequestDto.ChannelType, balancePayRequestDto.OSType);

        //    if (channelFactoryService == null)
        //    {
        //        throw new ArgumentException("选定的付款渠道暂时无法使用。");
        //    }

        //    if (balancePayRequestDto.OrderType != PaymentOrderType.Order)
        //    {
        //        throw new ArgumentException("付款订单类型仅支持订单，不支持其他类型");
        //    }

        //    if (!channelFactoryService.ConfirmPayValidation(balancePayRequestDto.PaymentRecordId, balancePayRequestDto.ReferenceNumber, balancePayRequestDto.Password))
        //    {
        //        throw new ArgumentException("支付失败,请重试");
        //    }

        //    this.commonPaymentRecordService.UpodatePaymentRecordCheckSignTime(balancePayRequestDto.PaymentRecordId);

        //    PaymentRecordDto paymentRecordDto = this.commonPaymentRecordService.UpdatePaymentRecordStatusSuccess(balancePayRequestDto.PaymentRecordId);
        //    OrderDto orderDto = this.orderService.GetOrder(paymentRecordDto.ReferenceNumber);

        //    this.orderService.CheckSignCompleteToProcessOrderInformation(Payer.Shipper, orderDto.OrderNo, balancePayRequestDto.PaymentRecordId, PaymentChannelType.Balance, paymentRecordDto.Amount);

        //    return this.Ok();
        //}
        //#endregion

        #region 回单支付
        /// <summary>
        /// 调起应用支付完成后验签（支付宝、微信、银行卡使用此接口）
        /// </summary>
        /// <param name="rechargeRequestDto">支付支付验签请求信息。</param>
        /// <response code="200">订单付款二维码信息。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [Obsolete]
        public IActionResult CheckSign([FromBody] RechargeRequestDto rechargeRequestDto)
        {
            if (rechargeRequestDto.ChannelType == PaymentChannelType.Balance)
            {
                throw new ArgumentException("此方法不支持余额支付");
            }

            //if (rechargeRequestDto.ChannelType == PaymentChannelType.Cash)
            //{
            //    throw new ArgumentException("此方法不支持线下支付");
            //}

            if (rechargeRequestDto.ChannelType == PaymentChannelType.BankCard)
            {
                throw new ArgumentException("此方法暂不支持银行卡支付");
            }

            IChannelFactoryService channelFactoryService = this.paymentService.GetChannelService(SourceAppType.StaffApp, rechargeRequestDto.ChannelType, rechargeRequestDto.OSType);

            if (channelFactoryService == null)
            {
                throw new ArgumentException("选定的付款渠道暂时无法使用。");
            }

            //if (rechargeRequestDto.OrderType != PaymentOrderType.Order)
            //{
            //    throw new ArgumentException("订单支付验签，不支持其他类型");
            //}

            if (rechargeRequestDto.Parameters == null || rechargeRequestDto.Parameters.Count == 0)
            {
                throw new ArgumentException("验签缺少必要信息,请检查Parameters是否存在信息");
            }

            PaymentRecordDto paymentRecordDto = channelFactoryService.SyncCheckSign(rechargeRequestDto.Parameters);

            if (paymentRecordDto.CheckSignTime == null && paymentRecordDto.Status == PaymentResultType.Success)
            {
                // 同步原始订单状态
                this.paymentService.AgentSynchronize(this.Admin, paymentRecordDto);
            }

            //if (paymentRecordDto.CheckSignTime.HasValue)
            //{
            //    PaymentDto paymentDto = new PaymentDto()
            //    {
            //        PaymentRecordId = paymentRecordDto.PaymentRecordId,
            //        OrderType = paymentRecordDto.OrderType,
            //        ReferenceNumber = paymentRecordDto.ReferenceNumber,
            //        PayChannelType = rechargeRequestDto.ChannelType,
            //        OriginalAmount = paymentRecordDto.Amount,
            //        Discount = 0M,
            //        PaidAmount = paymentRecordDto.Amount,
            //        Result = PaymentResultType.Success
            //    };
            //    this.orderService.CheckSignCompleteToProcessOrderInformation(Payer.Shipper, paymentRecordDto.ReferenceNumber, paymentRecordDto.PaymentRecordId, rechargeRequestDto.ChannelType, paymentRecordDto.Amount);
            //}

            return this.Ok();
        }

        #endregion

        #region 获取提现预授权信息
        /// <summary>
        /// 获取预授权登录信息。
        /// </summary>
        /// <param name="dto">预授渠道权信息。</param>
        /// <response code="200">预授权结果。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(Dictionary<string, string>), 200)]
        public IActionResult AppAuthLogin([FromBody] AuthLoginRequestDto dto)
        {
            IChannelFactoryService channelFactoryService = this.paymentService.GetChannelService(SourceAppType.StaffApp, dto.ChannelType, dto.OSType);

            if (channelFactoryService == null)
            {
                throw new ArgumentException("选定的授权渠道暂时无法使用。");
            }
            return this.Ok(channelFactoryService.CreateAppAuthLogin(SourceAppType.StaffApp, dto.OSType, null));
        }

        /// <summary>
        /// 授权登录用户的相关信息。
        /// </summary>
        /// <param name="dto">预授渠道权信息。</param>
        /// <response code="200">预授权结果。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(Dictionary<string, string>), 200)]
        public IActionResult AuthLoginInfo([FromBody] AuthLoginInfoRequestDto dto)
        {
            IChannelFactoryService channelFactoryService = this.paymentService.GetChannelService(SourceAppType.StaffApp, dto.ChannelType, dto.OSType);

            if (channelFactoryService == null)
            {
                throw new ArgumentException("选定的授权渠道暂时无法使用。");
            }
            return this.Ok(channelFactoryService.AuthLoginInfo(dto.Parameters["auth_code"], SourceAppType.StaffApp, dto.OSType, null));
        }
        #endregion


        #region 充值并获取支付二维码
        /// <summary>
        /// 充值并获取支付二维码（网页使用）
        /// </summary>
        /// <param name="requestDto">支付请求</param>
        /// <response code="201">充值</response>
        /// <response code="400">请求参数或输入的数据不正确。</response>
        /// <response code="500">服务器发生错误。</response>
        /// <response code="501">某些功能尚未实现。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [Log("充值并获取支付二维码（网页使用）")]
        [ProducesResponseType(typeof(string), 201)]
        public IActionResult QRCode([FromBody] PaymentRequestDto requestDto)
        {
            if (string.IsNullOrWhiteSpace(Admin.AddressIp)||Admin.AddressIp== "未知IP地址")
            {
                throw new ArgumentException(" 代理商IP地址错误,不可充值 ");
            }
            var channelService = this.paymentService.GetChannelService(requestDto.AppType,
                requestDto.ChannelType, requestDto.OSType);
            var subject = this.paymentBusinessService.GetPaymentSubject(requestDto, out decimal amount);
            var paymentDto = channelService.AgentGenerateQRCode(requestDto.AppType, requestDto.OrderType, subject,
                requestDto.ReferenceNumber, requestDto.OSType, requestDto.DeviceType, requestDto.DeviceId,
                requestDto.Parameters, amount, null, Admin);

            //QRCodeHelper qrGenerator = new QRCodeHelper();
            //QRCodeData qrCodeData = qrGenerator.CreateQrCode(HttpUtility.UrlDecode(paymentDto.Token), QRCodeHelper.ECCLevel.H);
            //QRCode qrCode = new QRCode(qrCodeData);
            //Bitmap qrCodeImage = qrCode.GetGraphic(5);
            //MemoryStream stream = new MemoryStream();
            //qrCodeImage.Save(stream, ImageFormat.Png);

            //return File(stream.ToArray(), "image/png");
            paymentDto.QRUrl = HttpUtility.UrlDecode(paymentDto.Token);
            return Ok(paymentDto);
        }

        /// <summary>
        /// 支付
        /// </summary>
        /// <param name="requestDto"></param>
        /// <returns></returns>
        [HttpPost("[action]")]
        [Log("支付(App使用)")]
        [ProducesResponseType(typeof(PaymentDto), 201)]
        public IActionResult PaymentRecord([FromBody] PaymentRequestDto requestDto)
        {
            if (string.IsNullOrWhiteSpace(Admin.AddressIp) || Admin.AddressIp == "未知IP地址")
            {
                throw new ArgumentException(" 代理商IP地址错误,不可充值 ");
            }
            var channelService = this.paymentService.GetChannelService(requestDto.AppType, requestDto.ChannelType, requestDto.OSType);
            var subject = this.paymentBusinessService.GetPaymentSubject(requestDto, out decimal amount);
            var paymentDto = channelService.AgentTryPay(requestDto.AppType, requestDto.OrderType, subject,
                requestDto.ReferenceNumber, requestDto.OSType, requestDto.DeviceType, requestDto.DeviceId,
                requestDto.Parameters, amount, null, this.Admin);

            return StatusCode((int)HttpStatusCode.Created, paymentDto);
        }

        #endregion

        #region 查询支付结果
        /// <summary>
        /// 查询支付结果
        /// </summary>
        /// <response code="200">获取支付渠道列表。</response>
        /// <returns></returns>
        [HttpGet("{payment_record_id}")]
        [ProducesResponseType(typeof(PaymentDto), 201)]
        public IActionResult Result([FromRoute(Name = "payment_record_id")] long paymentRecordId)
        {
            var result = this.commonPaymentRecordService.GetPaymentRecord(paymentRecordId);
            return this.Ok(result);
        }
        #endregion
    }
}
